package com.example.chat.server.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.group.ChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import io.netty.channel.ChannelHandler.Sharable;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;

@Slf4j
@Sharable
@Component
public class ChatServerHandler extends ChannelInboundHandlerAdapter {

    // 用于存储用户ID的属性键
    private static final AttributeKey<String> USER_ID = AttributeKey.newInstance("userId");

    @Autowired
    private ChannelGroup channelGroup;

    @Autowired
    private ConcurrentMap<String, Channel> userChannelMap;

    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        String userId = generateUserId(channel);
        
        // 将用户ID存储在channel属性中
        channel.attr(USER_ID).set(userId);
        
        channelGroup.add(channel);
        userChannelMap.put(userId, channel);
        log.info("有一个客户端加入: {}", userId);
        
        // 发送欢迎消息
        TextWebSocketFrame welcomeMsg = new TextWebSocketFrame(
                String.format("{\"type\":\"system\",\"message\":\"欢迎加入聊天室！你的ID是: %s\"}", userId));
        channel.writeAndFlush(welcomeMsg);
        
        // 通知其他用户有新用户加入（使用用户ID，让前端生成一致的昵称）
        TextWebSocketFrame joinMsg = new TextWebSocketFrame(
                String.format("{\"type\":\"system\",\"message\":\"用户 %s 加入了聊天室\"}", userId));
        channelGroup.stream()
                .filter(ch -> ch != channel)
                .forEach(ch -> ch.writeAndFlush(joinMsg));
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        String userId = channel.attr(USER_ID).get();
        
        if (userId != null) {
            channelGroup.remove(channel);
            userChannelMap.remove(userId);
            log.info("有一个客户端离开: {}", userId);
            
            // 通知其他用户有用户离开（使用用户ID，让前端生成一致的昵称）
            TextWebSocketFrame leaveMsg = new TextWebSocketFrame(
                    String.format("{\"type\":\"system\",\"message\":\"用户 %s 离开了聊天室\"}", userId));
            channelGroup.writeAndFlush(leaveMsg);
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Channel channel = ctx.channel();
        String userId = channel.attr(USER_ID).get();

        if (msg instanceof TextWebSocketFrame) {
            TextWebSocketFrame textFrame = (TextWebSocketFrame) msg;
            String request = textFrame.text();
            log.info("收到客户端 {} 的消息: {}", userId, request);

            // 广播消息到所有客户端
            TextWebSocketFrame response = new TextWebSocketFrame(
                    String.format("{\"type\":\"chat\",\"user\":\"%s\",\"message\":\"%s\"}", userId, request));
            channelGroup.writeAndFlush(response);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            log.info("WebSocket握手完成");
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("连接出现异常: {}", cause.getMessage(), cause);
        ctx.close();
    }

    private String generateUserId(Channel channel) {
        InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress();
        return remoteAddress.getAddress().getHostAddress() + ":" + remoteAddress.getPort();
    }
}